import os
import secrets
import time
from fastapi import Request, HTTPException, status, Depends
from fastapi.security.api_key import APIKeyHeader
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from starlette.middleware.base import BaseHTTPMiddleware
from fastapi.responses import JSONResponse
from dotenv import load_dotenv
from app.utils.auth_utils import verify_token
from typing import Optional, Dict, Any

# 加载环境变量
load_dotenv()

# 从环境变量获取API密钥，如果不存在则生成一个新的
API_KEY = os.getenv("X_API_KEY")
if not API_KEY:
    # 生成一个安全的随机API密钥 (32字节 = 64个十六进制字符)
    API_KEY = secrets.token_hex(32)
    print(f"生成的API密钥: {API_KEY}")
    print("请将此API密钥添加到.env文件中，变量名为X_API_KEY")

# 定义API密钥头部
API_KEY_HEADER = APIKeyHeader(name="X-API-Key", auto_error=False)

class APIKeyMiddleware(BaseHTTPMiddleware):
    """
    API密钥验证中间件
    检查请求头中是否包含有效的X-API-Key
    """
    
    async def dispatch(self, request: Request, call_next):
        # 排除不需要验证API密钥的路径
        exclude_paths = ["/", "/docs", "/redoc", "/openapi.json"]
        if request.url.path in exclude_paths:
            return await call_next(request)
            
        # 获取请求头中的API密钥
        api_key = request.headers.get("X-API-Key")
        
        # 如果没有提供API密钥或API密钥无效，则返回401未授权错误
        if not api_key or api_key != API_KEY:
            # 在中间件中，我们需要直接返回响应而不是抛出异常
            return JSONResponse(
                status_code=status.HTTP_401_UNAUTHORIZED,
                content={
                    "code": status.HTTP_401_UNAUTHORIZED,
                    "message": "无效的API密钥",
                    "data": None,
                    "timestamp": str(int(time.time()))
                },
                headers={"WWW-Authenticate": "ApiKey"}
            )
            
        # 如果API密钥有效，则继续处理请求
        return await call_next(request)

class JWTBearer(HTTPBearer):
    """JWT身份验证器"""
    def __init__(self, auto_error: bool = True):
        super(JWTBearer, self).__init__(auto_error=auto_error)
    
    async def __call__(self, request: Request) -> Dict[str, Any]:
        """
        验证JWT令牌并返回载荷
        
        Args:
            request: FastAPI请求对象
            
        Returns:
            令牌载荷
            
        Raises:
            HTTPException: 验证失败时抛出HTTP异常
        """
        # 排除登录和健康检查路径
        if request.url.path in ["/api/auth/login", "/health"]:
            return {}
            
        credentials: HTTPAuthorizationCredentials = await super(JWTBearer, self).__call__(request)
        if credentials:
            if not credentials.scheme == "Bearer":
                raise HTTPException(status_code=403, detail="认证方案无效")
            
            # 验证JWT令牌
            payload = self._verify_jwt_token(credentials.credentials)
            if not payload:
                raise HTTPException(status_code=403, detail="令牌无效或已过期")
                
            return payload
        else:
            raise HTTPException(status_code=403, detail="认证凭据无效")
    
    def _verify_jwt_token(self, token: str) -> Optional[Dict[str, Any]]:
        """
        验证JWT令牌
        
        Args:
            token: JWT令牌
            
        Returns:
            令牌载荷或None
        """
        return verify_token(token)

# 创建JWT身份验证实例
jwt_bearer = JWTBearer()